import React from 'react';
import { Upload, message, Progress, Button } from 'antd';
import useUploadOss from '@/hooks/useUploadOss';

import { FileList } from '../index';
import { getErrors, dataToFileList, fileListToData, generateUploadResource } from '../utils';

/**
 * 结合antd的Upload实现
 *
 * value的public格式为[{uid: Number, url: String, status: String}]的JSON字符串形式
 *
 * value的private格式为[{categoryCode,keyNameAndOpt:[]}]
 *
 * rules 目前支持三种内建校验 [{ max: 3}, {type: ['jpg', 'png']}, {length: 10}]
 *
 * 自定义校验可以{ validator: Function, message: String }
 */

// 自定义上传进度
const UploadProgress = ({ fileList }) =>
    fileList
        .filter(item => item.status && item.status !== 'done')
        .map(item => <Progress key={item.uid} percent={item.percent} size="small" />);

const UploadOssCompact = (props, ref) => {
    const {
        children,
        draggable = false,
        rules,
        value,
        onChange,
        showButton = {}, // 文件列表按钮配置 { preview:Boolean, download:Boolean, delete:Boolean }
        triggerType = 'button', // 默认使用包含button的模式
        editable = true,
        ossType = 'public', // 兼容oss的私有桶与公共桶
        categoryCode,
        onResourceChange,
        emptyText = '',
        ...rest
    } = props;

    const [uploadFile] = useUploadOss();

    // 必须要和form的value解耦，因为status会频繁更新
    const [showFileList, setShowFileList] = React.useState([]);

    // props => state
    React.useEffect(() => {
        setShowFileList(dataToFileList(value, ossType));
    }, [value, ossType]);

    // state => props
    const proxyOnChange = nextList => {
        onChange(fileListToData(nextList, ossType));
    };

    // 兼容旧的oss方式
    const [uploadResource, setUploadResource] = React.useState([]);
    React.useEffect(() => {
        if (onResourceChange) onResourceChange(generateUploadResource(uploadResource, categoryCode));
    }, [JSON.stringify(uploadResource)]);

    // 校验
    const beforeUpload = file => {
        const checkError = getErrors(rules, file, [...showFileList, file]);
        if (checkError) {
            message.error(checkError);
        }
        return !checkError;
    };

    const customRequest = async options => {
        const { onSuccess, onError, file, onProgress } = options;

        const result = await uploadFile(file, {
            ossType,
            onProgress: number => {
                onProgress({ percent: number });
            }
        });

        if (result) {
            onSuccess(result);
        } else {
            onError();
        }
    };

    const onRemove = file => {
        const exist = showFileList.find(item => item.uid === file.uid) ?? {};
        proxyOnChange(showFileList.filter(item => item !== exist));

        // 调用服务端删除资源接口
        if (ossType === 'private') {
            // 存在已上传的数据，重点
            if (exist.url?.includes('http')) {
                setUploadResource([...uploadResource, { ...file, action: 'DELETE' }]);
            } else {
                setUploadResource(uploadResource.filter(item => item.uid !== exist.uid));
            }
        }
    };

    const handleChange = ({ file, fileList }) => {
        if (file.status) {
            const nextList = fileList.map(item => ({ ...item, ...(item.response ? { url: item.response } : {}) }));
            setShowFileList(nextList);

            // 只有完成才需要更新表单状态
            if (file.status === 'done') {
                proxyOnChange(nextList);

                if (ossType === 'private') {
                    setUploadResource([...uploadResource, { ...file, action: 'ADD' }]);
                }
            }
        }
    };

    const Component = draggable ? Upload.Dragger : Upload;

    const showButtonCfg = {
        ...showButton,
        delete: editable
    };

    const renderTriggerArea = () => {
        if (!editable) return null;
        if (triggerType === 'button') {
            return <Button icon="upload">上传文件</Button>;
        }
        return children;
    };

    return (
        <>
            <Component
                ref={ref}
                customRequest={customRequest}
                onRemove={onRemove}
                onChange={handleChange}
                fileList={showFileList}
                beforeUpload={beforeUpload}
                showUploadList={false}
                {...rest}
            >
                {renderTriggerArea()}
            </Component>
            <UploadProgress fileList={showFileList} />
            <FileList fileList={showFileList} onDelete={onRemove} showButton={showButtonCfg} emptyText={emptyText} />
        </>
    );
};

export default React.forwardRef(UploadOssCompact);
